package com.intellagric.agriecom.service.recommend.service;

import com.intellagric.agriecom.module.recommend.RecommendServiceIN;
import com.intellagric.pojo.AgriecomProduce;

import com.intellagric.pojo.RecommendTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @Auther: zhy
 * @Date: 2019/5/8
 * @Description: 推荐服务
 */
@Service
public class RecommendService implements RecommendServiceIN {

    @Autowired
    private RuleService ruleService;

    @Autowired
    private RecommendModelService recommendModelService;

    @Autowired
    private ProductRecommendService productService;


    /**
     * 根据推荐栏位的ID查询推荐结果，并根据推荐规则进行整合排序
     *
     * @param columnId 栏位id
     * @param userId    用户id
     * @return List<Product>
     */
    public List<AgriecomProduce> recomend(int columnId, String userId) {
        List<AgriecomProduce> recommendResult = new ArrayList<>();
        //判断当前广告位是否有对应的推荐模型,如果没有推荐推荐模型就返回NULL
        RecommendTemplate template = ruleService.getTemplateByColumnId(columnId);
        if (template == null) {
            return recommendResult;
        }
        //根据广告位使用推荐模型计算的结果，每个广告位都有独立的一个或者多个模型进行支撑
        recommendResult = getRecommendResult(columnId, template.getNum(), userId);
        //对硬推商品进行设置
        /*setSaleAd(template.getDefaultProducts(), recommendResult);*/
        return recommendResult;
    }


    /**
     * 每个广告位都有独立的推荐模型支撑，模型是不能通用的。
     *
     * @param adId    广告位的编号
     * @param needNum 广告位需要推荐的商品数量
     * @param userId  当前访问的用户编号
     * @return List<Product>
     */
    private List<AgriecomProduce> getRecommendResult(int adId, int needNum, String userId) {
        List<AgriecomProduce> list = new ArrayList<>();
        //默认推荐协同过滤推荐
        //获取基于用户的相似度推荐结果，批处理计算出来的
        List<String> baseUserProductList = recommendModelService.recommendByUserCF(userId, needNum);
        //根据商品的id数组获取商品的详细信息
        List<AgriecomProduce> baseUserProductsReal = productService.baseInfo(baseUserProductList);
        //校验当前商品的状态
        checkProduct(baseUserProductsReal);

        //获取基于物品的离线推荐结果，前一天晚上计算出来的,根据用户昨天浏览的商品编号计算的
        List<String> baseItemList = recommendModelService.recommendByItemCF(userId, needNum);
        List<AgriecomProduce> baseItemProductsReal = productService.baseInfo(baseItemList);
        checkProduct(baseItemProductsReal);

        //获取默认的推荐结果
        List<String> defaultIdsList = recommendModelService.defaultRecommend(adId);
        List<AgriecomProduce> defaultList = productService.baseInfo(defaultIdsList);
        checkProduct(defaultList);

        //对推荐结果进行排序，排序算法根据需求来的
        for (int i = 1; i <= needNum; i++) {
            if ((i % 2 == 0)) {
                //封装基于物品的实时推荐结果,如果元素不够，就从默认的推荐推荐结果中获取
                getFirstValidItem(list, baseItemProductsReal, defaultList);
            } else {
                //封装基于用户的实时推荐结果，如果元素不够，就从默认的推荐推荐结果中获取
                getFirstValidItem(list, baseUserProductsReal, defaultList);
            }
        }

        return list;
    }


    /**
     * 将销售出去的硬广插入其中
     *
     * @param products
     * @param recommendResult
     */
    private void setSaleAd(Map<Integer, AgriecomProduce> products, List<AgriecomProduce> recommendResult) {
        if (products.size() > 0) {
            for (Integer index : products.keySet()) {
                if (index.intValue() <= recommendResult.size() && index.intValue() >= 0) {
                    //这里的实现，是直接替代 某个位置上已经存在的结果。
                    recommendResult.set((index.intValue() - 1), products.get(index));
                }
            }
        }
    }

    /**
     * 校验商品有效性
     *
     * @param recommendList 推荐的商品List
     */
    private void checkProduct(List<AgriecomProduce> recommendList) {
        int size = recommendList.size();
        for (int i = 0; i < size; i++) {
            //如果商品状态为下线状态，将商品移除掉 1--上线 2--下线
            /*if (!"1".equals(recommendList.get(i).getProductStatus())) {
                recommendList.remove(i);
                i--;
                size--;
            }*/
        }
    }


    /**
     * 从原始推荐商品List中获取一个有效的元素存放到目标List中
     * 如果原始推荐商品List中没有足够多的元素，就从默认推荐的结果中获取。
     *
     * @param tarList 目标List
     * @param orgList 原始List
     * @param defaultList 默认的推荐商品List
     */
    private void getFirstValidItem(List<AgriecomProduce> tarList, List<AgriecomProduce> orgList, List<AgriecomProduce> defaultList) {
        //当前的推荐商品结果为空时，从默认的推荐商品中加载
        if (orgList == null || orgList.size() < 1) {
            tarList.add(defaultList.get(0));
            defaultList.remove(0);
        }
        AgriecomProduce product = null;
        //去重
        if (orgList != null && orgList.size() > 0) {
            do {
                product = orgList.get(0);
                orgList.remove(0);
            } while (product != null && tarList.contains(product));
            tarList.add(product);
        }
    }




}
